//
// Created by 33145 on 2023/6/2.
//

#include "tcp_acceptor.h"
#include "../common/rocket.h"

#include <sys/socket.h>
#include <cstring>

namespace rocket {


  TCPAcceptor::TCPAcceptor(const NetAddr::ptr& local_addr) : _local_addr(local_addr) {
    if (!local_addr->checkValid()) {
      LOG_ERROR("invalid local addr [%s]", local_addr->toString().c_str());
      exit(0);
    }
    _family = local_addr->getFamily();
    _listen_fd = socket(_family, SOCK_STREAM, 0);
    if (_listen_fd < 0) {
      LOG_ERROR("socket create error");
      exit(0);
    }
    int val = 1;
    if (setsockopt(_listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != 0) {
      LOG_ERROR("setsockopt REUSEADDR error, errno=%d, error=%s", errno, strerror(errno));
      exit(0);
    }
    socklen_t len = _local_addr->getSockLen();
    if (bind(_listen_fd, _local_addr->getSockAddr(), len) != 0) {
      LOG_ERROR("bind error, errno=%d, error=%s", errno, strerror(errno));
      exit(0);
    }
    if (listen(_listen_fd, 1000) != 0) {
      LOG_ERROR("listen error, errno=%d, error=%s", errno, strerror(errno));
      exit(0);
    }
  }

  std::pair<int, NetAddr::ptr> TCPAcceptor::accept() const {
    sockaddr_in client_addr{};
    memset(&client_addr, 0, sizeof client_addr);
    socklen_t client_lin = sizeof client_addr;

    int client_fd = ::accept(_listen_fd, reinterpret_cast<sockaddr*> (&client_addr), &client_lin);
    if (client_fd < 0) {
      LOG_ERROR("accept error, errno=%d, error=%s", errno, strerror(errno));
      exit(0);
    }
    IPNetAddr::ptr peer_addr = std::make_shared<IPNetAddr>(client_addr);
    LOG_INFO("A client have accpeted succ, peer addr [%s]", peer_addr->toString().c_str());
    return std::make_pair(client_fd, peer_addr);
  }

  int TCPAcceptor::getListenFd() const {
    return _listen_fd;
  }
}